﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using System.Windows;
using Wpf_Examples.Models;

namespace Wpf_Examples.Tools
{
   public class CreateParticleBallWaveHelper
    {
        /// <summary>
        /// 存储所有粒子的列表。
        /// </summary>
        private readonly List<ParticleBallModel> _particleList;

        /// <summary>
        /// 用于绘制粒子的3D几何模型。
        /// </summary>
        private readonly GeometryModel3D _particleModel;

        /// <summary>
        /// 鼠标的半径影响范围，默认值为30。
        /// </summary>
        private readonly int MOUSERADIUS = 30;

        /// <summary>
        /// X方向上的粒子数量。
        /// </summary>
        private int XParticleCount;

        /// <summary>
        /// Y方向上的粒子数量。
        /// </summary>
        private int YParticleCount;

        /// <summary>
        /// 获取粒子模型。
        /// </summary>
        public Model3D ParticleModel => _particleModel;

        /// <summary>
        /// 构造函数，初始化粒子系统。
        /// </summary>
        /// <param name="amountX">X方向上的粒子数量。</param>
        /// <param name="amountY">Y方向上的粒子数量。</param>
        /// <param name="color">粒子的颜色。</param>
        public CreateParticleBallWaveHelper(int amountX, int amountY, Color color)
        {
            XParticleCount = amountX;
            YParticleCount = amountY;

            _particleList = new List<ParticleBallModel>();
            _particleModel = new GeometryModel3D { Geometry = new MeshGeometry3D() };
            var material = new DiffuseMaterial(new SolidColorBrush(color));
            _particleModel.Material = material;
        }

        /// <summary>
        /// 初始化粒子的位置和大小。
        /// </summary>
        /// <param name="radius">粒子的半径。</param>
        public void SpawnParticle(double radius)
        {
            // 初始化粒子位置和大小
            for (int ix = 0; ix < XParticleCount; ix++)
            {
                for (int iy = 0; iy < YParticleCount; iy++)
                {
                    var p = new ParticleBallModel
                    {
                        Position = new Point3D(ix * radius * 2, iy * radius * 2, 0),
                        Radius = radius,
                    };
                    _particleList.Add(p);
                }
            }
        }

        /// <summary>
        /// 根据鼠标位置更新粒子的半径。
        /// </summary>
        /// <param name="mp">鼠标位置。</param>
        public void Update(Point mp)
        {
            Random rand = new Random();
            foreach (var p in _particleList)
            {
                // 计算鼠标位置到粒子中心的距离
                double distance = Math.Sqrt(Math.Pow(mp.X - p.Position.X, 2) + Math.Pow(mp.Y - p.Position.Y, 2));
                // 调整高度逻辑，使粒子高度随距离变化
                double maxHeight = 50; // 最大高度限制
                double baseHeight = 0; // 基础高度
                double height = Math.Max(baseHeight, maxHeight * Math.Exp(-distance / MOUSERADIUS) + rand.NextDouble() * 10 - 5);
                p.Position = new Point3D(p.Position.X, p.Position.Y, height);
            }
            UpdateGeometry();
        }

        /// <summary>
        /// 更新几何体的数据。
        /// </summary>
        private void UpdateGeometry()
        {
            var positions = new Point3DCollection();
            var normals = new Vector3DCollection();
            var textureCoordinates = new PointCollection();
            var indices = new Int32Collection();

            // 清空旧的数据，防止数据叠加
            positions.Clear();
            normals.Clear();
            textureCoordinates.Clear();
            indices.Clear();

            // 遍历所有粒子，更新几何体数据
            foreach (var p in _particleList)
            {
                // 创建球体的几何体
                CreateSphereGeometry(p.Position, p.Radius, positions, normals, textureCoordinates, indices);
            }

            // 更新几何体的数据
            ((MeshGeometry3D)_particleModel.Geometry).Positions = positions;
            ((MeshGeometry3D)_particleModel.Geometry).Normals = normals;
            ((MeshGeometry3D)_particleModel.Geometry).TextureCoordinates = textureCoordinates;
            ((MeshGeometry3D)_particleModel.Geometry).TriangleIndices = indices;
        }

        /// <summary>
        /// 创建球体的几何体。
        /// </summary>
        /// <param name="center">球体的中心位置。</param>
        /// <param name="radius">球体的半径。</param>
        /// <param name="positions">顶点位置集合。</param>
        /// <param name="normals">法线向量集合。</param>
        /// <param name="textureCoordinates">纹理坐标集合。</param>
        /// <param name="indices">三角形索引集合。</param>
        private void CreateSphereGeometry(Point3D center, double radius, Point3DCollection positions, Vector3DCollection normals, PointCollection textureCoordinates, Int32Collection indices)
        {
            const int segments = 20;
            const int rings = 20;

            for (int i = 0; i < rings; i++)
            {
                double v0 = (double)i / (rings - 1);
                double v1 = (double)(i + 1) / (rings - 1);
                double phi0 = v0 * Math.PI;
                double phi1 = v1 * Math.PI;

                for (int j = 0; j < segments; j++)
                {
                    double u0 = (double)j / (segments - 1);
                    double u1 = (double)(j + 1) / (segments - 1);
                    double theta0 = u0 * 2.0 * Math.PI;
                    double theta1 = u1 * 2.0 * Math.PI;

                    Point3D p0 = new Point3D(
                        center.X + radius * Math.Sin(phi0) * Math.Cos(theta0),
                        center.Y + radius * Math.Sin(phi0) * Math.Sin(theta0),
                        center.Z + radius * Math.Cos(phi0)
                    );

                    Point3D p1 = new Point3D(
                        center.X + radius * Math.Sin(phi1) * Math.Cos(theta0),
                        center.Y + radius * Math.Sin(phi1) * Math.Sin(theta0),
                        center.Z + radius * Math.Cos(phi1)
                    );

                    Point3D p2 = new Point3D(
                        center.X + radius * Math.Sin(phi1) * Math.Cos(theta1),
                        center.Y + radius * Math.Sin(phi1) * Math.Sin(theta1),
                        center.Z + radius * Math.Cos(phi1)
                    );

                    Point3D p3 = new Point3D(
                        center.X + radius * Math.Sin(phi0) * Math.Cos(theta1),
                        center.Y + radius * Math.Sin(phi0) * Math.Sin(theta1),
                        center.Z + radius * Math.Cos(phi0)
                    );

                    positions.Add(p0);
                    positions.Add(p1);
                    positions.Add(p2);
                    positions.Add(p3);

                    normals.Add(new Vector3D(p0.X, p0.Y, p0.Z));
                    normals.Add(new Vector3D(p1.X, p1.Y, p1.Z));
                    normals.Add(new Vector3D(p2.X, p2.Y, p2.Z));
                    normals.Add(new Vector3D(p3.X, p3.Y, p3.Z));

                    textureCoordinates.Add(new Point(u0, v0));
                    textureCoordinates.Add(new Point(u0, v1));
                    textureCoordinates.Add(new Point(u1, v1));
                    textureCoordinates.Add(new Point(u1, v0));

                    int index = positions.Count - 4;
                    indices.Add(index);
                    indices.Add(index + 1);
                    indices.Add(index + 2);
                    indices.Add(index);
                    indices.Add(index + 2);
                    indices.Add(index + 3);
                }
            }
        }
    }
}
